package com.javasm.boot.oauth2.filter;

import com.javasm.boot.oauth2.entity.Response;
import com.javasm.boot.oauth2.utils.WebUtils;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus;
import org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Author：MoDebing
 * Version：1.0
 * Date：2022-12-20-23:27
 * Description:
 */
@Component
@AllArgsConstructor
public class MyFilter extends OncePerRequestFilter {

    private WebUtils webUtils;

    private TokenStore tokenStore;

    @Bean
    @Lazy
    public ResourceServerTokenServices resourceServerTokenServices(){
        DefaultTokenServices services = new DefaultTokenServices();
        services.setTokenStore(tokenStore);
        return services;
    }



    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String requestURI = request.getRequestURI();
        String flag = request.getParameter("flag");
        if (!StringUtils.pathEquals(requestURI,"/oauth/token") || StringUtils.hasText(flag)){
            String refreshToken = request.getParameter("refreshToken");
            Response resp;
            if (refreshToken != null) {
                OAuth2RefreshToken oAuth2RefreshToken = tokenStore.readRefreshToken(refreshToken);
                if (isExpired(oAuth2RefreshToken)) {
                    tokenStore.removeRefreshToken(oAuth2RefreshToken);
                    resp = new Response().msg("Invalid refresh token (expired): " + refreshToken).code(HttpStatus.BAD_REQUEST);
                    webUtils.renderString(resp,response);
                    return;
                }
            }
            String tokenBearer = request.getHeader("Authorization");
            if (StringUtils.hasText(tokenBearer)&&tokenBearer.contains("Bearer ")){
                String token = tokenBearer.substring(7);

                try {
                    this.resourceServerTokenServices().loadAuthentication(token);
                } catch (Throwable e) {
                    Response errorInfo = new Response().code(HttpStatus.BAD_REQUEST).msg(e.getMessage());
                    webUtils.renderString(errorInfo,response);
                    return;
                }
            }
            filterChain.doFilter(request,response);
            return;
        }
        Response resp = new Response().code(HttpStatus.BAD_REQUEST).msg("非法请求");
        webUtils.renderString(resp,response);
    }


    public boolean isExpired(OAuth2RefreshToken refreshToken) {
        if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
            ExpiringOAuth2RefreshToken expiringToken = (ExpiringOAuth2RefreshToken) refreshToken;
            return expiringToken.getExpiration() == null
                    || System.currentTimeMillis() > expiringToken.getExpiration().getTime();
        }
        return false;
    }

}
